package junior.db.dao.mybatis.interceptor;

import com.google.common.collect.Maps;
import junior.db.dao.base.IEntityWrapper;
import junior.db.dao.ext.IBatchExtensible;
import junior.db.dao.ext.IExtensible;
import junior.db.dao.ext.IExtHandler;
import junior.db.dao.ext.ExtWrapper;
import junior.db.dao.ext.ExtHandlerRegistry;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MybatisExtHelper {
    private static ThreadLocal<Map<Class<?>, ExtWrapper>> extCache = ThreadLocal.withInitial(() -> Maps.newConcurrentMap());
    
    public static void putExt(ExtWrapper ext) {
        extCache.get().put(ext.getEntityClass(), ext);
    }
    
    public static void removeExt(ExtWrapper ext) {
        extCache.get().remove(ext.getEntityClass());
    }
    
    static ExtWrapper popExt(Class<?> entityClass) {
        Map<Class<?>, ExtWrapper> map = extCache.get();
        if (map.isEmpty()) {
            return null;
        }
        for (Iterator<Map.Entry<Class<?>, ExtWrapper>> ite = map.entrySet().iterator(); ite.hasNext();) {
            Map.Entry<Class<?>, ExtWrapper> entry = ite.next();
            if (entry.getKey().isAssignableFrom(entityClass)) {
                ite.remove();
                return entry.getValue();
            }
        }
        return null;
    }
    
    /**
     * 执行扩展
     * @param arg1
     */
    static Object doExt(Object arg1) {
        if (arg1 instanceof IEntityWrapper) {
            Class<?> entityClass = ((IEntityWrapper) arg1).getEntityClass();
            ExtWrapper ext = popExt(entityClass);
            if (ext == null) {
                return null;
            }
            if (arg1 instanceof IExtensible) {
                if (ext.getExt() != null) {
                    return ((IExtensible) arg1).doExt(ext.getExt(), ext.getExtFields());
                } else {
                    IExtensible param = ((IExtensible) arg1).doEntityExt(ext.getExtFields());
                    if (param != arg1) {
                        return param;
                    }
                }
                List<IExtHandler> handlers = ExtHandlerRegistry.getHandlers();
                if (handlers != null) {
                    for (IExtHandler handler : handlers) {
                        handler.onExt((IExtensible) arg1);
                    }
                }
            }
            if (arg1 instanceof IBatchExtensible) {
                if (ext.getExts() != null) {
                    return ((IBatchExtensible) arg1).doExt(ext.getExts(), ext.getExtFields());
                } else {
                    IBatchExtensible param = ((IBatchExtensible) arg1).doEntityExt(ext.getExtFields());
                    if (param != arg1) {
                        return param;
                    }
                }
                List<IExtHandler> handlers = ExtHandlerRegistry.getHandlers();
                if (handlers != null) {
                    for (IExtHandler handler : handlers) {
                        handler.onBatchExt((IBatchExtensible) arg1);
                    }
                }
            }
        }
        return null;
    }
    
}
